package com.atguigu.gmall.index.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.bean.PageResultVo;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.index.config.GmallCache;
import com.atguigu.gmall.index.config.RedissonConfig;
import com.atguigu.gmall.index.feign.GmallPmsClient;
import com.atguigu.gmall.index.service.IndexService;
import com.atguigu.gmall.index.utils.DistributedLock;
import com.atguigu.gmall.pms.entity.CategoryEntity;
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;


import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author: 86182
 * @Date: 2021/8/10
 * @Time: 18:18
 * @Version:
 */
@Service
public class IndexServiceImpl implements IndexService {
    @Autowired
    private GmallPmsClient pmsClient;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private DistributedLock lock;
    @Autowired
    private RedissonClient redissonClient;

    String uuid = UUID.randomUUID().toString();
    private static final String KEY_PREFIX = "index:cates:";
    private static final String LOCK_PREFIX = "index:cates:lock:";

    public List<CategoryEntity> queryLvl1Categories(){
        ResponseVo<List<CategoryEntity>> responseVoCategory = this.pmsClient.queryCategoryByPid(0l);
        List<CategoryEntity> categoryEntities = responseVoCategory.getData();
        return categoryEntities;
    }

    @GmallCache(prefix = KEY_PREFIX,timeout = 259200,random = 43200,lock = LOCK_PREFIX)
    @Override
    public List<CategoryEntity> queryLvl2WithSubsByPid(Long pid) {
        ResponseVo<List<CategoryEntity>> responseVo = this.pmsClient.queryLvl2WithSubsByPid(pid);
        List<CategoryEntity> categoryEntities = responseVo.getData();
        return categoryEntities;
    }

//    @Override
//    public List<CategoryEntity> queryLvl2WithSubsByPid(Long pid) {
//        // 1. 先查询缓存 , 如果命中,直接返回
//        String json = this.redisTemplate.opsForValue().get(KEY_PREFIX + pid);
//        if (StringUtils.isNotBlank(json)){
//            return JSON.parseArray(json,CategoryEntity.class);
//        }
//        //为了防止缓存击穿,添加分布式锁
//        RLock lock = this.redissonClient.getLock(LOCK_PREFIX + pid);
//        lock.lock();
//        // 在阻塞获取分布式锁的过程中,可能有其他请求已经放入缓存了,此时再次确认缓存中是否存在,存在直接返回
//        String json2 = this.redisTemplate.opsForValue().get(KEY_PREFIX + pid);
//        if (StringUtils.isNotBlank(json2)){
//            return JSON.parseArray(json2,CategoryEntity.class);
//        }
//        try {
//            //2.没有命中,直接远程调用查询数据库,放入缓存
//            ResponseVo<List<CategoryEntity>> responseVo = this.pmsClient.queryLvl2WithSubsByPid(pid);
//            List<CategoryEntity> categoryEntities = responseVo.getData();
//            //为了防止缓存穿透,数据即使为null也缓存,只是缓存时间较短,一般不超过5min
//            if (CollectionUtils.isEmpty(categoryEntities)){
//                this.redisTemplate.opsForValue().set(KEY_PREFIX + pid,JSON.toJSONString(categoryEntities),5, TimeUnit.MINUTES);
//            }else {
//                this.redisTemplate.opsForValue().set(KEY_PREFIX + pid,JSON.toJSONString(categoryEntities),90 + new Random().nextInt(15), TimeUnit.DAYS);
//            }
//            return categoryEntities;
//        } finally {
//            lock.unlock();
//        }
//    }

   // @Override
//    public void testLock2()  {
//        String uuid = UUID.randomUUID().toString();
//        Boolean lock = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);
//        if (!lock){
//            //获取锁失败,自旋
//            try {
//                Thread.sleep(100);
//                testLock();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        } else {
//            String number = this.redisTemplate.opsForValue().get("number");
//            if (StringUtils.isBlank(number)){
//                this.redisTemplate.opsForValue().set("number","1");
//                return;
//            }
//            int num = Integer.parseInt(number);
//            this.redisTemplate.opsForValue().set("number",String.valueOf(++num));
//            //释放锁
//            //为了防止误删,先判断是否自己的锁
//            String script = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";
//            this.redisTemplate.execute(new DefaultRedisScript<>(script,Boolean.class),Arrays.asList("lock"),uuid);
////            if (StringUtils.equals(uuid,this.redisTemplate.opsForValue().get("lock"))){
////                this.redisTemplate.delete("lock");
////            }
//        }
//    }


//    public void testLock3()  {
//        String uuid = UUID.randomUUID().toString();
//        Boolean lock = this.lock.lock("lock", uuid, 30);
//        if (lock){
//            String number = this.redisTemplate.opsForValue().get("number");
//            if (StringUtils.isBlank(number)){
//            this.redisTemplate.opsForValue().set("number","1");
//            }
//            int num = Integer.parseInt(number);
//            this.redisTemplate.opsForValue().set("number", String.valueOf(++num));
//            this.lock.unlock("lock",uuid);
//        }
//    }


//    @Override
//    public void testLock()  {
//            // 加锁
//        RLock lock = this.redissonClient.getLock("lock");
//
//
//        try {
//            lock.lock();
//            String number = this.redisTemplate.opsForValue().get("number");
//            if (StringUtils.isBlank(number)){
//                this.redisTemplate.opsForValue().set("number","1");
//            }
//            int num = Integer.parseInt(number);
//            this.redisTemplate.opsForValue().set("number", String.valueOf(++num));
//            try {
//                TimeUnit.SECONDS.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        } finally {
//            lock.unlock();
//        }
//    }

    public static void main(String[] args) {
        BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),20,0.3);
        bloomFilter.put("1");
        bloomFilter.put("2");
        bloomFilter.put("3");
        bloomFilter.put("4");
        bloomFilter.put("5");
        bloomFilter.put("6");
        bloomFilter.put("7");
        System.out.println(bloomFilter.mightContain("1"));
        System.out.println(bloomFilter.mightContain("3"));
        System.out.println(bloomFilter.mightContain("5"));
        System.out.println(bloomFilter.mightContain("7"));
        System.out.println(bloomFilter.mightContain("8"));
        System.out.println(bloomFilter.mightContain("9"));
        System.out.println(bloomFilter.mightContain("10"));
        System.out.println(bloomFilter.mightContain("11"));
        System.out.println(bloomFilter.mightContain("12"));
        System.out.println(bloomFilter.mightContain("13"));
        System.out.println(bloomFilter.mightContain("14"));
        System.out.println(bloomFilter.mightContain("15"));
        System.out.println(bloomFilter.mightContain("16"));
        System.out.println(bloomFilter.mightContain("17"));
        System.out.println(bloomFilter.mightContain("18"));
    }
}










